/* eslint-disable max-len */
export default class CanvasContext {
  constructor(webCanvasContext,canvas) {
    this.canvas = canvas
    this.webCanvasContext = webCanvasContext
    this.setting = {}
    this.actions = []
  }

  arc() {
    this.actions.push({ name: "arc", args: arguments })
  }

  arcTo() {
    this.actions.push({ name: "arcTo", args: arguments })
  }

  beginPath() {
    this.actions.push({ name: "beginPath", args: arguments })
  }

  bezierCurveTo() {
    this.actions.push({ name: "bezierCurveTo", args: arguments })
  }

  clearRect() {
    this.actions.push({ name: "clearRect", args: arguments })
  }

  clip() {
    this.actions.push({ name: "clip", args: arguments })
  }

  closePath() {
    this.actions.push({ name: "closePath", args: arguments })
  }

  createCircularGradient() {
    const wx_x = arguments[0]
    const wx_y = arguments[1]
    const wx_r = arguments[2]
    const args = [wx_x, wx_y, 0, wx_x, wx_y, wx_r]
    return this.webCanvasContext.createRadialGradient.apply(this.webCanvasContext, args)
  }

  createLinearGradient() {
    return this.webCanvasContext.createLinearGradient.apply(this.webCanvasContext, arguments)
  }

  async createPattern() {
    const run = (wx_image, wx_repetition) => {
      return new Promise((resolve) => {
        const img = new Image()
        img.onload = () => {
          const pattern = this.webCanvasContext.createPattern(img, wx_repetition)
          resolve(pattern)
        }
        img.src = wx_image
      })
    }
    const wx_image = arguments[0]
    const wx_repetition = arguments[1]
    return await run(wx_image, wx_repetition)
  }

  draw(reserve = false, callback) {
    if (!reserve) {
      this.webCanvasContext.clearRect(0, 0, this.canvas.width, this.canvas.height)
    }
    for (const action of this.actions) {
      const name = action.name
      let args = action.args
      switch (name) {
      case "setLineDash": {
        const wx_pattern = args[0]
        this.webCanvasContext.lineDashOffset = args[1]
        args = [wx_pattern]
        break;
      }
      case "setTransform":
      case "transform": {
        const wx_scaleX = args[0]
        const wx_skewX = args[1]
        const wx_skewY = args[2]
        const wx_scaleY = args[3]
        const wx_translateX = args[4]
        const wx_translateY = args[5]
        args = [wx_scaleX, wx_skewY, wx_skewX, wx_scaleY, wx_translateX, wx_translateY]
        break;
      }
      case "setFillStyle":
      case "setFontSize":
      case "setGlobalAlpha":
      case "setLineCap":
      case "setLineJoin":
      case "setLineWidth":
      case "setMiterLimit":
      case "setShadow":
      case "setStrokeStyle":
      case "setTextAlign": {
        let web_name = name.slice(3)
        web_name = web_name.charAt(0).toLowerCase()+ web_name.slice(1)
        this.webCanvasContext[web_name] = args[0]
        break
      }
      case "setTextBaseline": {
        const wx_textBaseline = args[0]
        let web_textBaseline
        switch (wx_textBaseline) {
        case "top":
        case "bottom":
        case "middle":
          web_textBaseline = wx_textBaseline
          break
        case "normal":
          web_textBaseline = "alphabetic"
          break
        default:
          return
        }
        this.webCanvasContext.textBaseline = web_textBaseline
        break
      }
      case "fillStyle":
      case "strokeStyle":
      case "shadowOffsetX":
      case "shadowOffsetY":
      case "shadowColor":
      case "shadowBlur":
      case "lineWidth":
      case "lineCap":
      case "lineJoin":
      case "miterLimit":
      case "lineDashOffset":
      case "font":
      case "globalAlpha":
      case "globalCompositeOperation":
        this.webCanvasContext[name] = args[0]
        break
      default:
        this.webCanvasContext[name].apply(this.webCanvasContext, args)
        break;
      }
    }

    if (callback) {
      callback()
    }
    // return this.webCanvasContext.draw(reserve, callback)
  }

  drawImage() {
    this.actions.push({ name: "drawImage", args: arguments })
  }

  fill() {
    this.actions.push({ name: "fill", args: arguments })
  }

  fillRect() {
    this.actions.push({ name: "fillRect", args: arguments })
  }

  fillText() {
    this.actions.push({ name: "fillText", args: arguments })
  }

  lineTo() {
    this.actions.push({ name: "lineTo", args: arguments })
  }

  measureText() {
    this.actions.push({ name: "measureText", args: arguments })
  }

  moveTo() {
    this.actions.push({ name: "moveTo", args: arguments })
  }

  quadraticCurveTo() {
    this.actions.push({ name: "quadraticCurveTo", args: arguments })
  }

  rect() {
    this.actions.push({ name: "rect", args: arguments })
  }

  restore() {
    this.actions.push({ name: "restore", args: arguments })
  }

  rotate() {
    this.actions.push({ name: "rotate", args: arguments })
  }

  save() {
    this.actions.push({ name: "save", args: arguments })
  }

  scale() {
    this.actions.push({ name: "scale", args: arguments })
  }

  //
  set fillStyle(color) {
    this.setting.fillStyle = color
    this.actions.push({ name: "fillStyle", args: arguments })
  }

  get fillStyle() {
    return this.setting.fillStyle
  }

  setFillStyle() {
    this.actions.push({ name: "setFillStyle", args: arguments })
  }

  //
  set font(fontSize) {
    this.setting.fillStyle = fontSize
    this.actions.push({ name: "font", args: arguments })
  }

  get font() {
    return this.setting.fillStyle
  }


  setFontSize() {
    this.actions.push({ name: "setFillStyle", args: arguments })
  }

  //
  set globalAlpha(alpha) {
    this.setting.globalAlpha = alpha
    this.actions.push({ name: "globalAlpha", args: arguments })
  }

  get globalAlpha() {
    return this.setting.globalAlpha
  }

  setGlobalAlpha() {
    this.actions.push({ name: "setFillStyle", args: arguments })
  }

  //
  set lineCap(lineCap) {
    this.setting.lineCap = lineCap
    this.actions.push({ name: "lineCap", args: arguments })
  }

  get lineCap() {
    return this.setting.lineCap
  }

  setLineCap() {
    this.actions.push({ name: "setLineCap", args: arguments })
  }

  //
  set lineDashOffset(offset) {
    this.setting.lineDashOffset = offset
    this.actions.push({ name: "lineDashOffset", args: arguments })
  }

  get lineDashOffset() {
    return this.setting.lineDashOffset
  }

  setLineDash() {
    this.actions.push({ name: "setLineDash", args: arguments })
  }

  //
  set lineJoin(lineJoin) {
    this.setting.lineJoin = lineJoin
    this.actions.push({ name: "lineJoin", args: arguments })
  }

  get lineJoin() {
    return this.setting.lineJoin
  }

  setLineJoin() {
    this.actions.push({ name: "setLineJoin", args: arguments })
  }

  //
  set lineWidth(lineWidth) {
    this.setting.lineWidth = lineWidth
    this.actions.push({ name: "lineWidth", args: arguments })
  }

  get lineWidth() {
    return this.setting.lineWidth
  }

  setLineWidth() {
    this.actions.push({ name: "setLineWidth", args: arguments })
  }

  //
  set miterLimit(miterLimit) {
    this.setting.miterLimit = miterLimit
    this.actions.push({ name: "miterLimit", args: arguments })
  }

  get miterLimit() {
    return this.setting.miterLimit
  }

  setMiterLimit() {
    this.actions.push({ name: "setMiterLimit", args: arguments })
  }

  //
  set shadowOffsetX(offsetX) {
    this.setting.offsetX = offsetX
    this.actions.push({ name: "shadowOffsetX", args: arguments })
  }

  get shadowOffsetX() {
    return this.setting.offsetX
  }

  set shadowOffsetY(offsetY) {
    this.setting.offsetY = offsetY
    this.actions.push({ name: "shadowOffsetY", args: arguments })
  }

  get shadowOffsetY() {
    return this.setting.offsetY
  }

  set shadowBlur(blur) {
    this.setting.shadowBlur = blur
    this.actions.push({ name: "shadowBlur", args: arguments })
  }

  get shadowBlur() {
    return this.setting.shadowBlur
  }

  set shadowColor(color) {
    this.setting.shadowColor = color
    this.actions.push({ name: "shadowColor", args: arguments })
  }

  get shadowColor() {
    return this.setting.shadowColor
  }

  setShadowBlur() {
    this.actions.push({ name: "setShadowBlur", args: arguments })
  }


  //
  set strokeStyle(color) {
    this.setting.strokeStyle = color
    this.actions.push({ name: "strokeStyle", args: arguments })
  }

  get strokeStyle() {
    return this.setting.strokeStyle
  }

  setStrokeStyle() {
    this.actions.push({ name: "setStrokeStyle", args: arguments })
  }

  //
  set textAlign(align) {
    this.setting.textAlign = align
    this.actions.push({ name: "textAlign", args: arguments })
  }

  get textAlign() {
    return this.setting.textAlign
  }

  setTextAlign() {
    this.actions.push({ name: "setTextAlign", args: arguments })
  }

  //
  set textBaseline(textBaseline) {
    this.setting.textBaseline = textBaseline
    this.actions.push({ name: "textBaseline", args: arguments })
  }

  get textBaseline() {
    return this.setting.textBaseline
  }

  setTextBaseline() {
    this.actions.push({ name: "setTextBaseline", args: arguments })
  }

  setTransform() {
    this.actions.push({ name: "setTransform", args: arguments })
  }

  stroke() {
    this.actions.push({ name: "stroke", args: arguments })
  }

  strokeRect() {
    this.actions.push({ name: "strokeRect", args: arguments })
  }

  strokeText() {
    this.actions.push({ name: "strokeText", args: arguments })
  }

  transform() {
    this.actions.push({ name: "transform", args: arguments })
  }

  translate() {
    this.actions.push({ name: "translate", args: arguments })
  }
}
